home *** CD-ROM | disk | FTP | other *** search
- /*
- Author: Andrew Lowry
-
- Columbia University Center for Computing Activities, July 1986.
- Copyright (C) 1986, 1987, Trustees of Columbia University in the City
- of New York. Permission is granted to any individual or institution
- to use, copy, or redistribute this software so long as it is not sold
- for profit, provided this copyright notice is retained.
- */
- /* cmnoi
- **
- ** This module contains the default break table and handlers for
- ** parsing noise words. Parsing succeeds if the current input
- ** begins with a left paren, then matches the given noise word
- ** modulo case and whitespace, then closes with a right paren.
- ** If the current input begins with anything other than a left
- ** paren, parsing also succeeds, but no characters are consumed.
- ** Unusual handling is performed when the current input is empty
- ** and the CM_PFE flag is on in the CSB. In this case, the noise
- ** word with parentheses is stuffed into the command buffer, and
- ** another parse attempt is requested. (We cannot merely succeed,
- ** since the characters we stuff into the buffer are not in the
- ** text buffer that was passed to us. The caller must rebuild
- ** this text buffer for us.) Another unusual case is when the
- ** input is empty and the CM_ACT flag is on in the CSB, indicating
- ** that action is pending. In this case, the parse succeeds,
- ** consuming no characters, so that the action will apply to
- ** the next real field, not to the noise word. Finally,
- ** noise word parses do not affect the atom buffer.
- **
- ** Completion can only occur with a non-empty buffer (due to the
- ** special action with CM_ACT and an empty buffer just described).
- ** (This is not true if completion is immediate on some key, but if
- ** that's the case, something strange is probably going on anyway.)
- ** The completion text consists of the remainder of the noise word,
- ** with closing paren and trailing space. Partial completion will
- ** complete only up to and including the next punctuation, and will
- ** not add a trailing blank.
- **
- ** Help, like completion, should never occur at the beginning of
- ** a noise word. It consists of the string, "Noise word."
- **
- ** The break table has no effect on the parsing of a noise word.
- ** The default is set to include only the printing characters
- ** other than question mark, so that standard actions will be
- ** active. For first character, everything but left paren breaks,
- ** so that CM_WKF parsing will work correctly.
- **/
-
- #define NOIERR /* declare cmnoi parse errors here */
-
- #include "ccmdlib.h" /* get ccmd package symbols */
- #include "cmfncs.h" /* and internal symbols */
-
- /* Forward declarations of handlers */
-
- int noiprs(), noihlp(), noicplt();
-
- static brktab noibrk = {
- { /* only open paren allowed first */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- },
- { /* all print chars but '?' */
- 0xff, 0xbf, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
- }
- };
-
- ftspec ft_noi = { noiprs, noihlp, noicplt, 0, &noibrk }; /* handler structure */
-
-
-
- /* noiprs - If current input is empty and CM_PFE is on, stuff the noise
- ** word and ask for another try. If empty and CM_ACT is on, succeed
- ** consuming nothing. If nonempty and 1st char is not paren, succeed
- ** consuming nothing. Otherwise succeed if the rest matches the noise
- ** word string followed by a right paren and another character.
- **/
-
- PASSEDSTATIC int
- noiprs(text,textlen,fdbp,parselen,value)
- char *text;
- int textlen,*parselen;
- fdb *fdbp;
- pval *value;
- {
- int ret; /* results of stuffs */
- char *term; /* pointer to char after close paren */
- char *cplt; /* unused arg to fndnoi */
-
- cmcsb._cmflg |= CM_NAC; /* protect the atom buffer */
- if (textlen == 0) /* empty buffer? */
- if (cmcsb._cmflg & CM_PFE) { /* and prior field got completion? */
- ret = cmsti1('(',0); /* yup, give an open paren */
- if (ret == CMxOK)
- ret = cmsti((char *) fdbp->_cmdat,0); /* followed by the noise */
- if (ret == CMxOK)
- ret = cmsti(") ",0); /* followed by close paren and space */
- if (ret == CMxOK)
- ret = CMxAGN; /* and request another try */
- return(ret);
- }
- else if (cmcsb._cmflg & CM_ACT) { /* empty and action waiting? */
- *parselen = 0; /* consume nothing */
- return(CMxOK); /* and succeed */
- }
- else
- return(CMxINC); /* empty, no PFE, no action waiting */
-
- if ((*text & CC_CHR) != '(') { /* nonempty buffer not a noise word? */
- *parselen = 0; /* then consume nothing */
- return(CMxOK); /* and succeed - noise is optional */
- }
-
- /* find noise in the input */
- ret = fndnoi(text+1,textlen-1,(char *) fdbp->_cmdat,&cplt,&term);
- if (ret != CMxOK)
- return(ret); /* propagate errors */
- if (term == NULL)
- return(CMxINC); /* not terminated -- need more input */
- *parselen = term-text; /* compute length of noise */
- return(CMxOK); /* and succeed */
- }
-
-
-
- /* noihlp - Always print "Noise word" */
-
- PASSEDSTATIC int
- noihlp(text,textlen,fdbp,cust)
- char *text;
- int textlen,cust;
- fdb *fdbp;
- {
- cmxputs("noise word");
- return(CMxOK);
- }
-
-
-
- /* noicplt - Just finish up the noise where the current input
- ** leaves off. Full completion also adds a space, partial
- ** completion never does.
- **/
-
- PASSEDSTATIC int
- noicplt(text,textlen,fdbp,full,cplt,cpltlen)
- char *text,**cplt;
- int textlen,full,*cpltlen;
- fdb *fdbp;
- {
- int ret; /* return code from aux routine */
- char *term; /* char after noise word if any */
- char c; /* chars in completion */
- static char *work = NULL; /* dynamic area to build completion */
- char *cp; /* for copying completion text */
- char *malloc(); /* declare non-int library routine */
- int badalc = FALSE; /* true if malloc fails below */
-
- if (work != NULL) { /* buffer hanging around from last time? */
- free(work); /* get rid of it */
- work = NULL; /* and mark it released */
- }
- /* find noise in the input */
- ret = fndnoi(text+1,textlen-1,(char *) fdbp->_cmdat,cplt,&term);
-
- *cpltlen = -1; /* always complete to end of string */
- if (*cplt == NULL) { /* noise is all there */
- if (ret == CMxINC) /* no closing paren */
- *cplt = ")"; /* so give them one */
- }
- else { /* noise not all there */
- work = malloc(strlen(*cplt)+2); /* noise, paren, and null */
- if (work != NULL) { /* allocation succeeded? */
- cp = work; /* point to work space */
- while (*cp++ = *(*cplt)++); /* copy remainder of noise word */
- *(--cp) = ')'; /* finish with right paren */
- *(++cp) = NULCHAR; /* and tie off with a null */
- *cplt = work; /* point to constructed text */
- }
- else
- badalc = TRUE; /* flag allocation failure */
- }
- if (full) /* full completion */
- if (badalc)
- return(0); /* just fill in if allocation failed */
- else
- return(CMP_SPC | CMP_GO); /* otherwise add a space and a wakeup */
- else
- return(CMP_PNC); /* partial - complete to punctuation */
- }
-
-
-
- /* fndnoi - Auxiliary routine for noise word handlers
- **
- ** Determines how much of the noise word is in the input buffer,
- ** and indicates where completion, if any, should start.
- **
- ** Input parameters:
- ** text - The input text to be parsed.
- ** textlen - Size of the input text.
- ** noise - Pointer to the noise word.
- **
- ** Output parameters:
- ** cplt - A pointer to the start of completion text within the noise.
- ** term - A pointer to the character following the right paren if there
- ** was one in the input.
- **
- ** Returns: Standard error code. CMxOK means complete noise word with
- ** following terminator. CMxINC means good match so far, but needs
- ** more for a CMxOK. Anything else is error.
- **/
-
- static int
- fndnoi(text,textlen,noise,cplt,term)
- char *text,*noise,**cplt,**term;
- int textlen;
- {
- char cc,tc; /* completion and text chars */
- int ret;
- int inws = FALSE; /* TRUE during whitespace in completion */
-
- *term = NULL; /* assume no terminator */
- *cplt = noise; /* start completion all the way back */
-
- ret = skipws(&text,&textlen,FALSE); /* optional space after open paren */
- if (ret != CMxOK)
- return(ret); /* propagate errors */
-
- while ((cc = **cplt) != NULCHAR) /* loop to end of noise */
- if ((cc == SPACE) || (cc == TAB)) /* hit some white space */
- if (inws)
- (*cplt)++; /* already in it... keep looking */
- else {
- ret = skipws(&text,&textlen,TRUE); /* mandatory ws in text */
- if (ret != CMxOK)
- return(ret); /* propagate problems */
- inws = TRUE; /* don't need it again */
- (*cplt)++; /* and consume the character */
- }
- else if (textlen == 0) /* more noise and no more text? */
- return(CMxINC); /* yup, ask for more text */
- else {
- inws = FALSE; /* no longer in white space */
- tc = (*text++) & CC_CHR; /* try to match noise */
- if ((cc >= 'a') && (cc <= 'z'))
- cc -= 'a'-'A'; /* uppercase both chars */
- if ((tc >= 'a') && (tc <= 'z'))
- tc -= 'a'-'A';
- if (cc != tc) /* different chars? */
- return(NOIxNP); /* then no parse */
- textlen--; /* else update counts and pointers */
- (*cplt)++;
- } /* and keep looping */
-
- *cplt = NULL; /* got through whole noise - no completion */
-
- ret = skipws(&text,&textlen,FALSE); /* optional space before closing */
- if (ret != CMxOK)
- return(ret);
-
- if (textlen == 0) /* nothing left? */
- return(CMxINC); /* we still need a closing paren */
- else if ((*text & CC_CHR) != ')') /* next char not closing paren? */
- return(NOIxNP); /* then bad parse */
- else {
- if (textlen > 1) /* something after closing paren? */
- *term = text+1; /* yup, give them a pointer to it */
- return(CMxOK); /* entire noise word parsed ok */
- }
- }
-
-
-
- /* skipws - aux routine for fndnoi.
- **
- ** Purpose:
- ** Skips spaces and tabs in the input text. Fails if there are none
- ** and the mandatory flag was on in the call.
-
- ** Input parameters:
- ** text - Pointer to text to be scanned.
- ** textlen - Number of chars in text.
- ** mandatory - TRUE if an error should result if no space is there.
- **
- ** Output parameters:
- ** text, textlen - updated according to chars skipped.
- **
- ** Returns: Standard error code.
- **/
-
- static int
- skipws(text,textlen,mandatory)
- char **text;
- int *textlen,mandatory;
- {
- char c;
- while (*textlen > 0) { /* scan whole text */
- c = **text & CC_CHR; /* get next char */
- if ((c == SPACE) || (c == TAB)) {
- (*text)++; /* found white space - skip it */
- (*textlen)--; /* count it */
- mandatory = FALSE; /* and no longer mandatory */
- }
- else
- break; /* exit loop when non-ws found */
- }
-
- if (mandatory) /* no ws found and it was required? */
- if (*textlen == 0) /* yes, no input? */
- return(CMxINC); /* then it's incomplete */
- else
- return(NOIxNP); /* otherwise bad parse */
- else
- return(CMxOK); /* otherwise it's fine */
- }
-